package com.tencent.compose.sample

import androidx.compose.foundation.layout.*
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.material.Button
import test725.crash_in_c
import kotlinx.cinterop.ExperimentalForeignApi
import androidx.compose.ui.napi.JsEnv
import com.tencent.compose.utils.TsFoo
import com.tencent.compose.utils.TsEnv
import com.tencent.compose.utils.FooObject

import kotlinx.cinterop.*

@Composable
@OptIn(ExperimentalForeignApi::class)
internal fun Dfx() {
    // Replace Kotlin-managed array OOB (which throws) with a native-heap overflow
    // that can be detected by AddressSanitizer when the binary is built/linked with ASan.
    triggerHeapBufferOverflow()
    Column(Modifier.fillMaxWidth().fillMaxHeight().padding(30.dp)) {
        Button(onClick = {
            val arr = arrayOf(0, 1, 2);
            arr[3] = 3;
        }) {
            Text("C->K 崩溃")
        }

        Button(onClick = {
            crash_in_c()
        }) {
            Text("C->K->C 崩溃")
        }

        Button(onClick = {

        }) {
            Text("dump内存")
        }

        Button(onClick = {
            println("KN: js_leak start:")
            fooTest()
        }) {
            Text("触发js_leak")
        }
    }
}

// --- ASan test helpers ---
@OptIn(ExperimentalForeignApi::class)
fun triggerHeapBufferOverflow() {
    println("KN: triggerHeapBufferOverflow allocating 1 byte and writing 1024 bytes")
    val p = nativeHeap.allocArray<ByteVar>(1)
    // Overwrite far beyond the allocated 1 byte -> should trigger ASan heap-buffer-overflow
    // Use explicit writes to avoid C function signature mismatches.
    for (i in 0 until 1024) {
        p[i] = 0.toByte()
    }
    // Free (may not be reached if ASan aborts)
    nativeHeap.free(p)
}

@OptIn(ExperimentalForeignApi::class)
fun fooTest() {
    println("KN: fooTest call start:")
    val loopCount = 10

    val foo = FooObject(
        id = "rootId",
        boolValue = true,
        intValue = 1000,
        longValue = 10001000L,
        doubleValue = 101.2123,
        cache = arrayOf(FooObject(id = "id2", fooValue = FooObject(id = "id3", longValue = 20001000))),
        fooValue = FooObject(id = "id2", fooValue = FooObject(id = "id3", longValue = 20001000))
    )
    val global = JsEnv.getGlobal()
    val funcName = JsEnv.createStringUtf8("fooArkTsFunc1")
    val func1 = JsEnv.getProperty(global, funcName)
    println("KN: fooTest call start 2:")
    TsEnv.callFunction(global, func1, TsFoo.toNapiValue(foo))
}
